use std::collections::HashMap;

use crate::errors::AdminOpError;
use serde::{Deserialize, Serialize};
use sqlx::{mysql::MySqlRow, Row};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MockRouter {
    #[serde(default)]
    pub id: i32,
    #[serde(rename = "path", default)]
    pub route: String,
    #[serde(default)]
    pub group: String,
    #[serde(default)]
    pub method: String,
    #[serde(default)]
    pub headers: HashMap<String, String>,
    #[serde(default)]
    pub status_code: i32,
    #[serde(default)]
    pub content: String,
}

impl MockRouter {
    pub fn check_insert(&mut self) -> Result<(), AdminOpError> {
        if self.id != 0 {
            return Err(AdminOpError::InvalidParam(
                "insert data id can't be 0".to_string(),
            ));
        }
        if self.route == "" {
            return Err(AdminOpError::InvalidParam(
                "route can't be empty".to_string(),
            ));
        }
        if self.group == "" {
            return Err(AdminOpError::InvalidParam(
                "group can't be empty".to_string(),
            ));
        }
        if self.method == "" {
            return Err(AdminOpError::InvalidParam(
                "method can't be empty".to_string(),
            ));
        }
        if self.status_code == 0 {
            self.status_code = 200;
        }
        Ok(())
    }
    pub fn check_update(&mut self) -> Result<(), AdminOpError> {
        if self.id == 0 {
            return Err(AdminOpError::InvalidParam(
                "insert data id can't be 0".to_string(),
            ));
        }
        if self.route == "" {
            return Err(AdminOpError::InvalidParam(
                "route can't be empty".to_string(),
            ));
        }
        if self.group == "" {
            return Err(AdminOpError::InvalidParam(
                "group can't be empty".to_string(),
            ));
        }
        if self.method == "" {
            return Err(AdminOpError::InvalidParam(
                "method can't be empty".to_string(),
            ));
        }
        Ok(())
    }
    pub fn check_delete(&self) -> Result<(), AdminOpError> {
        if self.id == 0 {
            return Err(AdminOpError::InvalidParam(
                "delete data id can't be 0".to_string(),
            ));
        }
        Ok(())
    }
    pub fn serialize_headers(&self) -> String {
        let mut header_key_value: Vec<String> = Vec::new();
        for (key, value) in self.headers.iter() {
            header_key_value.push(format!("{}:{}", key, value));
        }
        header_key_value.join(",")
    }
}

impl From<MySqlRow> for MockRouter {
    fn from(row: MySqlRow) -> MockRouter {
        let mut router = MockRouter {
            id: row.get(0),
            route: row.get(1),
            group: row.get(2),
            method: row.get(3),
            headers: HashMap::new(),
            status_code: row.get(5),
            content: row.get(6),
        };
        let header_string: String = row.get(4);
        for header in header_string.split(',') {
            let kv: Vec<&str> = header.split(':').collect();
            router.headers.insert(kv[0].to_string(), kv[1].to_string());
        }
        router
    }
}
